package by.koleda.photoupdater.manager;

import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import android.content.ContentProviderOperation;
import android.content.ContentProviderOperation.Builder;
import android.content.ContentProviderResult;
import android.content.ContentValues;
import android.content.Context;
import android.content.OperationApplicationException;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.os.RemoteException;
import android.provider.ContactsContract;
import android.util.Log;
import by.koleda.photoupdater.helpers.ImageLoader;
import by.koleda.photoupdater.helpers.Utils;
import by.koleda.photoupdater.model.Contact;
import by.koleda.photoupdater.model.Profile;
import by.koleda.photoupdater.model.Suggestion;
import by.koleda.photoupdater.model.VkProfile;
import by.koleda.photoupdater.provider.PhotoContract;

public class ContactsManager {
	
	public static final String TAG = ContactsManager.class.getSimpleName();
			
	public static Cursor getContacts(Context context) {
		String[] projection = {
				ContactsContract.Contacts._ID,
				ContactsContract.Contacts.DISPLAY_NAME
		};
		String selection = ContactsContract.Contacts.HAS_PHONE_NUMBER + " <> 0 AND " 
				+ ContactsContract.Contacts.IN_VISIBLE_GROUP + " = '" + ("1") + "'";
		String sortOrder = ContactsContract.Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC";
		Cursor cursor = context.getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, projection, selection, null, sortOrder);
		
		if (cursor != null) {
			cursor.moveToFirst();
		}
		return cursor;
	}
	
	public static ArrayList<Contact> getContactList(Context context) {
		ArrayList<Contact> contactList = new ArrayList<Contact>();
		String selection = ContactsContract.Contacts.HAS_PHONE_NUMBER + " <> 0 AND " 
				+ ContactsContract.Contacts.IN_VISIBLE_GROUP + " = '" + ("1") + "'";
		Cursor cursor = context.getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, null, selection, null, null);
		int idIndex = cursor.getColumnIndex(ContactsContract.Contacts._ID);
		
		while (cursor.moveToNext()) {
			String contactId = cursor.getString(idIndex);
			Contact contact = new Contact();
			contact.setContactId(contactId);
			Cursor contactCursor = context.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = "+ contactId, null, null);
			while (contactCursor.moveToNext()) {
				String phoneNumber = contactCursor.getString(contactCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
				String displayName = contactCursor.getString(contactCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
				contact.setPhoneNumber(Utils.formatNumber(phoneNumber));
				contact.setDisplayName(displayName);
				break;
			}
			contactCursor.close();

			Cursor nameCursor = context.getContentResolver().query(ContactsContract.Data.CONTENT_URI, null, ContactsContract.Data.CONTACT_ID + " = " + contactId, null, null);
			while (nameCursor.moveToNext()) {
				String givenName = nameCursor.getString(nameCursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME));
				String familyName = nameCursor.getString(nameCursor.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME));
				contact.setFirstName(givenName);
				contact.setLastName(familyName);
				break;
			}
			nameCursor.close();
			contactList.add(contact);
		}
		cursor.close();
		return contactList;
	}
	
	public static ArrayList<String> getLinked(Context context) {
		ArrayList<String> linked = new ArrayList<String>();
		String[] projection = {
				PhotoContract.Suggestions.CONTACT_ID
		};
		
		Cursor cursor = context.getContentResolver().query(PhotoContract.Suggestions.CONTENT_URI, projection, PhotoContract.Suggestions.VKLINKED + " = 1 ", null, null);
		int contactIndex = cursor.getColumnIndex(PhotoContract.Suggestions.CONTACT_ID);
		while (cursor.moveToNext()) {
			linked.add(cursor.getString(contactIndex));
		}
		cursor.close();
		return linked;
	}
	
	public static ArrayList<Long> getVkLinked(Context context) {
		ArrayList<Long> vkLinked = new ArrayList<Long>();
		String[] projection = {
				PhotoContract.Suggestions.VKCONTACT_ID
		};
		
		Cursor cursor = context.getContentResolver().query(PhotoContract.Suggestions.CONTENT_URI, projection, PhotoContract.Suggestions.VKLINKED + " = 1 ", null, null);
		int vkContactIndex = cursor.getColumnIndex(PhotoContract.Suggestions.VKCONTACT_ID);
		while (cursor.moveToNext()) {
			vkLinked.add(cursor.getLong(vkContactIndex));
		}
		cursor.close();
		return vkLinked;
	}
	
	public static HashMap<String, Long> getVkMobilePhone(Context context) {
		HashMap<String, Long> vkMobilePhone = new HashMap<String, Long>();
		String[] projection = {
				PhotoContract.PhotoColumns.CONTACT_ID,
				PhotoContract.PhotoColumns.MOBILE_PHONE
		};
		Cursor cursor = context.getContentResolver().query(PhotoContract.PhotoColumns.CONTENT_URI, projection, PhotoContract.PhotoColumns.MOBILE_PHONE + " IS NOT NULL AND " + PhotoContract.PhotoColumns.MOBILE_PHONE + " <> '' ", null, null);
		int mobilePhoneIndex = cursor.getColumnIndex(PhotoContract.PhotoColumns.MOBILE_PHONE);
		int contactIdIndex = cursor.getColumnIndex(PhotoContract.PhotoColumns.CONTACT_ID);
		while (cursor.moveToNext()) {
			String phoneNumber = cursor.getString(mobilePhoneIndex);
			if (phoneNumber == null || phoneNumber.equals("null")) {
				continue;
			}
			phoneNumber = Utils.formatNumber(phoneNumber);
			vkMobilePhone.put(phoneNumber, cursor.getLong(contactIdIndex));
		}
		cursor.close();
		return vkMobilePhone;
	}
	
	public static HashMap<String, ArrayList<Long>> getVkFirstName(Context context) {
		HashMap<String, ArrayList<Long>> vkFirstName = new HashMap<String, ArrayList<Long>>();
		String[] projection = {
				PhotoContract.PhotoColumns.CONTACT_ID,
				PhotoContract.PhotoColumns.FIRST_NAME
		};
		Cursor cursor = context.getContentResolver().query(PhotoContract.PhotoColumns.CONTENT_URI, projection, PhotoContract.PhotoColumns.FIRST_NAME + " NOT NULL ", null, null);
		int firstNameIndex = cursor.getColumnIndex(PhotoContract.PhotoColumns.FIRST_NAME);
		int contactIdIndex = cursor.getColumnIndex(PhotoContract.PhotoColumns.CONTACT_ID);
		String firstName = null;
		Long contactId = null;
		ArrayList<Long> contactIdList = null;
		while (cursor.moveToNext()) {
			firstName = cursor.getString(firstNameIndex);
			contactId = cursor.getLong(contactIdIndex);
			if (vkFirstName.containsKey(firstName)) {
				contactIdList = vkFirstName.get(firstName);
				contactIdList.add(contactId);
				vkFirstName.put(firstName, contactIdList);
			} else {
				contactIdList = new ArrayList<Long>();
				contactIdList.add(contactId);
				vkFirstName.put(firstName, contactIdList);
			}
		}
		cursor.close();
		return vkFirstName;
	}
	
	public static HashMap<String, ArrayList<Long>> getVkLastName(Context context) {
		HashMap<String, ArrayList<Long>> vkLastName = new HashMap<String, ArrayList<Long>>();
		String[] projection = {
				PhotoContract.PhotoColumns.CONTACT_ID,
				PhotoContract.PhotoColumns.LAST_NAME
		};
		Cursor cursor = context.getContentResolver().query(PhotoContract.PhotoColumns.CONTENT_URI, projection, PhotoContract.PhotoColumns.LAST_NAME + " NOT NULL ", null, null);
		int lastNameIndex = cursor.getColumnIndex(PhotoContract.PhotoColumns.LAST_NAME);
		int contactIdIndex = cursor.getColumnIndex(PhotoContract.PhotoColumns.CONTACT_ID);
		String lastName = null;
		Long contactId = null;
		ArrayList<Long> contactIdList = null;
		while (cursor.moveToNext()) {
			lastName = cursor.getString(lastNameIndex);
			contactId = cursor.getLong(contactIdIndex);
			if (vkLastName.containsKey(lastName)) {
				contactIdList = vkLastName.get(lastName);
				contactIdList.add(contactId);
				vkLastName.put(lastName, contactIdList);
			} else {
				contactIdList = new ArrayList<Long>();
				contactIdList.add(contactId);
				vkLastName.put(lastName, contactIdList);
			}
		}
		cursor.close();
		return vkLastName;
	}
	
	
	public static ArrayList<Suggestion> getSuggestions(Context context, int points) {
		
		ArrayList<Suggestion> suggestionsList = new ArrayList<Suggestion>();
		Cursor cursor;
		if (points == 0) {
			cursor = context.getContentResolver().query(PhotoContract.Suggestions.CONTENT_URI, null, PhotoContract.Suggestions.VKLINKED + " = 0 ", null, PhotoContract.Suggestions.VKPOINTS + " DESC");
		} else {
			cursor = context.getContentResolver().query(PhotoContract.Suggestions.CONTENT_URI, null, PhotoContract.Suggestions.VKLINKED + " = 0 AND " + PhotoContract.Suggestions.VKPOINTS + " >= " + points, null, PhotoContract.Suggestions.VKPOINTS + " DESC");
		}
		if (cursor == null) {
			return null;
		}
		
		int contactIdIndex = cursor.getColumnIndex(PhotoContract.Suggestions.CONTACT_ID);
		int vcontactIdIndex = cursor.getColumnIndex(PhotoContract.Suggestions.VKCONTACT_ID);
		String firstName = null;
		String lastName = null;
		String displayName = null;
		String phoneNumber = null;
		String photoUrl = null;
		boolean selected = false;
		while (cursor.moveToNext()) {
			String contactId = cursor.getString(contactIdIndex);
			String vcontactId = cursor.getString(vcontactIdIndex);
			
			Cursor contactCursor = context.getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = "+ contactId, null, null);
			while (contactCursor.moveToNext()) {
				phoneNumber = contactCursor.getString(contactCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
				displayName = contactCursor.getString(contactCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
				break;
			}
			contactCursor.close();
			Cursor vkcontactCursor = context.getContentResolver().query(PhotoContract.PhotoColumns.CONTENT_URI, null, PhotoContract.PhotoColumns.CONTACT_ID + " = " + vcontactId, null, null);
			while (vkcontactCursor.moveToNext()) {
				firstName = vkcontactCursor.getString(vkcontactCursor.getColumnIndex(PhotoContract.PhotoColumns.FIRST_NAME));
				lastName = vkcontactCursor.getString(vkcontactCursor.getColumnIndex(PhotoContract.PhotoColumns.LAST_NAME));
				photoUrl = vkcontactCursor.getString(vkcontactCursor.getColumnIndex(PhotoContract.PhotoColumns.PHOTO_URL));
				break;
			}
			vkcontactCursor.close();
			if (points != 0) {
				selected = true;
			}
			Suggestion newSuggestion = new Suggestion(contactId, vcontactId, firstName, lastName, photoUrl, displayName, phoneNumber, selected);
			suggestionsList.add(newSuggestion);
		}
		cursor.close();
		
		return suggestionsList;
	}
	
	public static void submitSuggestion(Context context, String contactId, String vkUid, String photoUrl) {
		ArrayList<ContentProviderOperation> photoBatch = new ArrayList<ContentProviderOperation>();
		ArrayList<ContentProviderOperation> linkBatch = new ArrayList<ContentProviderOperation>();
		photoBatch.add(photoOperation(context, contactId, photoUrl));
		linkBatch.add(linkOperation(contactId, vkUid));
		try {
			context.getContentResolver().applyBatch(ContactsContract.AUTHORITY, photoBatch);
			context.getContentResolver().applyBatch(PhotoContract.CONTENT_AUTHORITY, linkBatch);
		} catch (Exception e) {
			Log.e(TAG, e.getMessage());
		}
	}
	
	public static int submitSuggestions(Context context, ArrayList<Suggestion> submitted) {
		ArrayList<ContentProviderOperation> photoBatch = new ArrayList<ContentProviderOperation>();
		ArrayList<ContentProviderOperation> linkBatch = new ArrayList<ContentProviderOperation>();
		for (Suggestion suggestion: submitted) {
			ContentProviderOperation operation = photoOperation(context, suggestion.getContactId(), suggestion.getPhotoUrl());
			if (operation != null) {
				photoBatch.add(operation);
				operation = null;
			}
			operation = linkOperation(suggestion.getContactId(), suggestion.getUid());
			if (operation != null) {
				linkBatch.add(operation);
			}
		}
		ContentProviderResult[] result;
		try {
			context.getContentResolver().applyBatch(ContactsContract.AUTHORITY, photoBatch);
			result = context.getContentResolver().applyBatch(PhotoContract.CONTENT_AUTHORITY, linkBatch);
			return result.length;
		} catch (Exception e) {
			e.printStackTrace();
			return -1;
		}
	}
	
	public static ContentProviderOperation photoOperation(Context context, String contactId, String photoUrl) {
		Bitmap bitmap = ImageLoader.get(context).getBitmap(photoUrl, null);
		ByteArrayOutputStream image = new ByteArrayOutputStream();
		bitmap.compress(Bitmap.CompressFormat.JPEG, 100, image);
		String rawContactId = null;
		String[] projection = new String[] { ContactsContract.RawContacts._ID };
		String where = ContactsContract.RawContacts.CONTACT_ID + " = ?";
		String[] selection = new String[] { String.valueOf(contactId) };
		Cursor cursor = context.getContentResolver().query(ContactsContract.RawContacts.CONTENT_URI, projection, where, selection, null);
		while (cursor.moveToNext()) {
			rawContactId = cursor.getString(cursor.getColumnIndex(ContactsContract.RawContacts._ID));
			break;
		}
		cursor.close();
		if (rawContactId != null) {
			String whereString = ContactsContract.Data.RAW_CONTACT_ID + " = " + 
					rawContactId + " AND " + ContactsContract.Data.MIMETYPE + " = '" + 
					ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE + "'";
			Cursor photoCursor = context.getContentResolver().query(ContactsContract.Data.CONTENT_URI, null, whereString, null, null);
			if (photoCursor.moveToNext()) {
				photoCursor.close();
				Builder contentOperation = ContentProviderOperation.newUpdate(ContactsContract.Data.CONTENT_URI);
				contentOperation.withSelection(ContactsContract.Data.CONTACT_ID + "=?" + " AND " + ContactsContract.Data.MIMETYPE + "=?", new String[]{String.valueOf(contactId), ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE});
				contentOperation.withValue(ContactsContract.CommonDataKinds.Photo.PHOTO, image.toByteArray());
				contentOperation.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE);
				contentOperation.withValue(ContactsContract.Data.IS_SUPER_PRIMARY, 1);
				return contentOperation.build();
			} else {
				photoCursor.close();
				Builder contentOperation = ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI);
				contentOperation.withValue(ContactsContract.Data.RAW_CONTACT_ID, rawContactId);
				contentOperation.withValue(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Photo.CONTENT_ITEM_TYPE);
				contentOperation.withValue(ContactsContract.CommonDataKinds.Photo.PHOTO, image.toByteArray());
				contentOperation.withValue(ContactsContract.Data.IS_SUPER_PRIMARY, 1);
				return contentOperation.build();
			}
		}
		return null;
	}
	
	public static ContentProviderOperation linkOperation(String contactId, String vkUid) {
		Builder contentOperation = ContentProviderOperation.newUpdate(PhotoContract.Suggestions.CONTENT_URI);
		contentOperation.withSelection(PhotoContract.Suggestions.CONTACT_ID + "=?" + " AND " + PhotoContract.Suggestions.VKCONTACT_ID + "=?", new String[]{String.valueOf(contactId), vkUid});
		contentOperation.withValue(PhotoContract.Suggestions.VKLINKED, 1);
		return contentOperation.build();
	}

	public static Profile getProfile(Context context, String contactId) {
		if (contactId == null) {
			return null;
		}
		
		Profile profile = null;
		
		Long vkUid = null;
		
		String[] contactProjection = {
				ContactsContract.Contacts.DISPLAY_NAME
		};
		
		String[] suggestionProjection = {
				PhotoContract.Suggestions.VKCONTACT_ID
		};
		
		String[] vkContactProjection = {
				PhotoContract.PhotoColumns.FIRST_NAME,
				PhotoContract.PhotoColumns.LAST_NAME,
				PhotoContract.PhotoColumns.HOME_PHONE,
				PhotoContract.PhotoColumns.MOBILE_PHONE
		};
		
		String contactQueryString = ContactsContract.Contacts._ID + " = " + contactId 
				+ " AND " + ContactsContract.Contacts.HAS_PHONE_NUMBER + " <> 0 " 
				+ " AND " + ContactsContract.Contacts.IN_VISIBLE_GROUP + " = '" + ("1") + "'";
		String suggestionQueryString = PhotoContract.Suggestions.CONTACT_ID + " = " + contactId + " AND " + PhotoContract.Suggestions.VKLINKED + " <> 0 ";
		
		Cursor contactCursor = context.getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, contactProjection, contactQueryString, null, null);
		
		int nameIndex = contactCursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
		
		while(contactCursor.moveToNext()) {
			profile = new Profile(contactId, contactCursor.getString(nameIndex));
			break;
		}
		contactCursor.close();
		
		
		Cursor suggestionCursor = context.getContentResolver().query(PhotoContract.Suggestions.CONTENT_URI, suggestionProjection, suggestionQueryString, null, null);
		while(suggestionCursor.moveToNext()) {
			profile.setVkLinked(true);
			vkUid = suggestionCursor.getLong(suggestionCursor.getColumnIndex(PhotoContract.Suggestions.VKCONTACT_ID));
			profile.setVkUid(vkUid);
			break;
		}
		suggestionCursor.close();
		if (vkUid == null) {
			return profile;
		}
		
		String vkContactQueryString = PhotoContract.PhotoColumns.CONTACT_ID + " = " + vkUid;
		
		Cursor vkContactCursor = context.getContentResolver().query(PhotoContract.PhotoColumns.CONTENT_URI, vkContactProjection, vkContactQueryString, null, null);
		while(vkContactCursor.moveToNext()) {
			profile.setVkFirstName(vkContactCursor.getString(vkContactCursor.getColumnIndex(PhotoContract.PhotoColumns.FIRST_NAME)));
			profile.setVkLastName(vkContactCursor.getString(vkContactCursor.getColumnIndex(PhotoContract.PhotoColumns.LAST_NAME)));
			profile.setVkHomePhone(vkContactCursor.getString(vkContactCursor.getColumnIndex(PhotoContract.PhotoColumns.HOME_PHONE)));
			profile.setVkMobilePhone(vkContactCursor.getString(vkContactCursor.getColumnIndex(PhotoContract.PhotoColumns.MOBILE_PHONE)));
			break;
		}
		vkContactCursor.close();
		return profile;
	}
	
	public static void addCorrectSuggestion(Context context, String contactId, String vkUid) {
		ContentValues contentValues = new ContentValues();
		contentValues.put(PhotoContract.Suggestions.CONTACT_ID, contactId);
		contentValues.put(PhotoContract.Suggestions.VKCONTACT_ID, vkUid);
		contentValues.put(PhotoContract.Suggestions.VKLINKED, 1);
		contentValues.put(PhotoContract.Suggestions.VKPOINTS, 6);
		
		Cursor cursor = context.getContentResolver().query(PhotoContract.Suggestions.CONTENT_URI, null, PhotoContract.Suggestions.CONTACT_ID + " = " + contactId + " AND " + PhotoContract.Suggestions.VKCONTACT_ID + " = " + vkUid, null, null);
		if (cursor.moveToFirst()) {
			int idIndex = cursor.getColumnIndex(PhotoContract.Suggestions._ID);
			int id = cursor.getInt(idIndex);
			context.getContentResolver().update(PhotoContract.Suggestions.buildSuggestionUri(String.valueOf(id)), contentValues, null, null);
		} else {
			context.getContentResolver().insert(PhotoContract.Suggestions.CONTENT_URI, contentValues);
		}
		cursor.close();
	}
	
	public static void addNewVkProfiles(Context context, List<VkProfile> p) {
		ArrayList<ContentProviderOperation> profilesBatch = new ArrayList<ContentProviderOperation>();
		int counter = 0;
		for (int i = 0; i < p.size(); i++) {
			VkProfile vkProfile = p.get(i);
			counter++;
			ContentValues contentValues = new ContentValues();
			contentValues.put(PhotoContract.PhotoColumns.CONTACT_ID, vkProfile.getUid());
			contentValues.put(PhotoContract.PhotoColumns.FIRST_NAME, vkProfile.getFirstName());
			contentValues.put(PhotoContract.PhotoColumns.LAST_NAME, vkProfile.getLastName());
			contentValues.put(PhotoContract.PhotoColumns.PHOTO_URL, vkProfile.getPhotoUrl());
			contentValues.put(PhotoContract.PhotoColumns.HOME_PHONE, vkProfile.getHomePhone());
			contentValues.put(PhotoContract.PhotoColumns.MOBILE_PHONE, vkProfile.getMobilePhone());
			
			Cursor cursor = context.getContentResolver().query(PhotoContract.PhotoColumns.CONTENT_URI, null, PhotoContract.PhotoColumns.CONTACT_ID + " = " + vkProfile.getUid(), null, null);
			if (cursor.moveToFirst()) {
				int idIndex = cursor.getColumnIndex(PhotoContract.PhotoColumns._ID);
				int contactId = cursor.getInt(idIndex);
				profilesBatch.add(ContentProviderOperation.newUpdate(PhotoContract.PhotoColumns.buildContactUri(String.valueOf(contactId))).withValues(contentValues).build());
			} else {
				profilesBatch.add(ContentProviderOperation.newInsert(PhotoContract.PhotoColumns.CONTENT_URI).withValues(contentValues).build());
			}
			cursor.close();
			if (counter == 100 || i == p.size()) {
				try {
					context.getContentResolver().applyBatch(PhotoContract.CONTENT_AUTHORITY, profilesBatch);
					profilesBatch = new ArrayList<ContentProviderOperation>();
					counter = 0;
				} catch (RemoteException e) {
					throw new RuntimeException("Problem applying batch operation", e);
				} catch (OperationApplicationException e) {
					throw new RuntimeException("Problem applying batch operation", e);
				}
			}
		}
	}
	
	public static void unlinkProfile(Context context, Profile profile) {
		ContentValues values = new ContentValues();
		values.put(PhotoContract.Suggestions.VKLINKED, 0);
		values.put(PhotoContract.Suggestions.CONTACT_ID, profile.getContactId());
		values.put(PhotoContract.Suggestions.VKCONTACT_ID, profile.getVkUid());
		values.put(PhotoContract.Suggestions.VKPOINTS, 0);
		String selection = PhotoContract.Suggestions.CONTACT_ID + " = " + profile.getContactId() 
				+ " AND " + PhotoContract.Suggestions.VKCONTACT_ID + " = " + String.valueOf(profile.getVkUid());
		context.getContentResolver().update(PhotoContract.Suggestions.CONTENT_URI, values, selection, null);
	}
}